package com.jiezuo.flowable.listener;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.flowable.common.engine.api.delegate.event.FlowableEvent;
import org.flowable.common.engine.api.delegate.event.FlowableEventListener;
import org.flowable.common.engine.impl.cfg.TransactionState;
import org.flowable.engine.HistoryService;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.delegate.event.impl.FlowableEntityWithVariablesEventImpl;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.task.service.impl.persistence.entity.TaskEntityImpl;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 *@Description 全局监听-工作流已办消息提醒
 *             isFailOnException() 返回true => 此监听器中的发生异常，会终止工作流，同时将异常向上抛出，以此触发全局事务起作用！！！
 *@Author 庞留杰
 *@Date2021/5/8 14:46
 *@Version V1.0
 **/
@Slf4j
@Component
@RequiredArgsConstructor
public class GlobalTaskCompletedListener implements FlowableEventListener {

    //    private final RuntimeService runtimeService;
    private final HistoryService historyService;
    private final RepositoryService repositoryService;

    @Override
    public void onEvent(FlowableEvent flowableEvent) {
        log.info(">>>>>>>>>>>>>>>>>> 进入工作流 TaskCompleted 全局监听器 >>>>>>>>>>>>>>>>>>");
//        WSClient wsClient = SpringUtil.getObject(WSClient.class);
        TaskEntityImpl taskEntity = (TaskEntityImpl) ((FlowableEntityWithVariablesEventImpl) flowableEvent).getEntity();
        String processInstanceId = taskEntity.getProcessInstanceId();
        String processDefinitionId = taskEntity.getProcessDefinitionId();
        /*************** 对于第一个节点跳过，防止重复调用(start)*******************/
        List<String> activityTypeFilter =  new ArrayList();
        activityTypeFilter.add("userTask");
        List<HistoricActivityInstance> collect = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId)
                .orderByHistoricActivityInstanceStartTime().asc().list()
                .stream().filter(his -> activityTypeFilter.contains(his.getActivityType())).collect(Collectors.toList());
        if (collect.size() == 1) {
            return;
        }
        /*************** 对于第一个节点跳过，防止重复调用(end)*******************/
        HistoricActivityInstance historicActivityInstance = collect.get(collect.size() - 1);
        Map<String, String> params = new HashMap<>();
        params.put("processInstanceId", processInstanceId);
        params.put("activityId", historicActivityInstance.getActivityId());
        params.put("activityName", historicActivityInstance.getActivityName());
        // HistoricActivityInstance currentActivityInstance = null;
        // if (collect.size() > 1) {
        //     currentActivityInstance = collect.get(collect.size() - 2);
        //     params.put("currentActivityId", currentActivityInstance.getActivityId());
        //     params.put("currentActivityName", currentActivityInstance.getActivityName());
        // }
        params.put("currentActivityId", taskEntity.getTaskDefinitionKey());
        params.put("currentActivityName", taskEntity.getName());
        System.out.println("taskEntity = " + taskEntity);
        System.out.println("processInstanceId = " + processInstanceId);
        System.out.println("processDefinitionId = " + processDefinitionId);
        /*ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        String processDefinitionId = processInstance.getProcessDefinitionId();*/
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(processDefinitionId).singleResult();
//        FinanceClient financeClient = SpringUtil.getObject(FinanceClient.class);
//        System.out.println("financeClient = " + financeClient);
//        Result result = financeClient.taskCompleted(params);
//        if (!result.isSuccess()) {
//            throw new BusinessRuntimeException(result.getMessage());//调用失败，抛出异常
//        }
//        try {
//            // 主要是为了触发下一步审核人的消息豆变化
//            CommonService commonService = SpringUtil.getObject(CommonService.class);
//            List<Map<String, String>> info = commonService.findTodoInfoByProcessInstanceId(processInstanceId);
//            String s = JSON.toJSONString(info); // 将参数转换一下，要不会传递失败
//            List<Map<String, String>> list = JSON.parseObject(s, new TypeReference<List<Map<String, String>>>() {
//            });
//            Result sentResult = wsClient.batchMessagePush(list);
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
    }

    /**
     * 当侦听器执行抛出异常时，当前操作是否应该失败。
     * isFailOnException()方法确定：当引发事件、onEvent(…)方法抛出异常时的行为。
     * 当返回false时，将忽略异常。当返回true时，异常不会被忽略，并且会出现向上冒泡传递（bubble up），实际上会使当前正在执行的命令失败。
     * 如果事件是API调用（或任何其他事务性操作，例如作业执行）的一部分，则事务将回滚。
     * 如果事件侦听器中的行为不是业务关键型的（business-critical），那么建议返回false。
     */
    @Override
    public boolean isFailOnException() {
        //return false;// PLJ 2024年4月24日14:18:46
        return true;
    }

    /** 返回此事件监听器是否在事件发生时立即触发，还是在事务生命周期事件上触发(在提交或回滚之前/之后)。
     *
     * isFireOnTransactionLifecycleEvent()方法确定此事件侦听器是在事件发生时立即触发，还是在由getOnTransaction()方法确定的事务生命周期事件（transaction lifecycle event）上触发。
     * 事务生命周期事件（transaction lifecycle event）支持的值为：
     *
     * 已提交（COMMITTED）
     * 已回滚（ROLLED_BACK）
     * 提交中（COMMITTING）
     * 回滚中（ROLLINGBACK）
     */
    @Override
    public boolean isFireOnTransactionLifecycleEvent() {
        return true;
    }

    /**
     * 如果非空，表示在当前事务的生命周期中触发事件的时间点。
     * 执行时机，需要配合{@link #isFireOnTransactionLifecycleEvent()}使用，
     * 执行时机类型：COMMITTED, ROLLED_BACK, COMMITTING, ROLLINGBACK
     * COMMITTING：事物提交前
     * COMMITTED：事物提交后
     * ROLLINGBACK：事物会滚前
     * ROLLED_BACK：事物会滚后
     *
     * @return COMMITTED/ROLLED_BACK/COMMITTING/ROLLINGBACK
     */
    @Override
    public String getOnTransaction() {
        //事务提交后触发
        return TransactionState.COMMITTED.name();
    }
}